package com.zoo.buyor.wechat.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zoo.buyor.user.adapter.UserAdapter;
import com.zoo.buyor.user.dao.UserDao;
import com.zoo.buyor.user.domain.entity.User;
import com.zoo.buyor.user.service.UserService;
import com.zoo.buyor.websocket.service.WebSocketService;
import com.zoo.buyor.wechat.adapter.TextBuilder;
import com.zoo.buyor.wechat.service.WxMsgService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class WxMsgServiceImpl implements WxMsgService {
    /**
     * openId和code的对应关系
     * key:openId
     * value:code
     */
    private static final ConcurrentHashMap<String, Integer> WAIT_AUTHORIZE_MAP = new ConcurrentHashMap<>();
    @Autowired
    UserDao userDao;
    @Autowired
    UserService userService;
    @Lazy
    @Autowired
    WxMsgService wxMsgService;
    @Autowired
    WebSocketService webSocketService;
    private String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    @Value("${buyor.wx.appId}")
    private String appId;
    @Value("${buyor.wx.callback}")
    private String redirect_uri;
    private String grantUrl;
    @PostConstruct
    private void grantUrlInit() {
        grantUrl = String.format(URL, appId, redirect_uri);
    }
    /**
     * 扫描二维码成功
     */
    @Override
    public WxMpXmlOutMessage scanQRCodeWithArgument(WxMpXmlMessage wxMpXmlMessage) {
        String openId = wxMpXmlMessage.getFromUser();
        Integer eventKey = getEventKey(wxMpXmlMessage);
        User user = userDao.getByOpenId(openId);
        //用户存在且openId与公众号端数据一致为已注册,用户存在且有头像昵称等信息为已授权
        boolean registered = Objects.nonNull(user);
        boolean authorized = registered && (StrUtil.isNotBlank(user.getAvatar()) && StrUtil.isNotBlank(user.getName()));
        //已注册
        if (registered) {
            //已授权
            if (authorized) {
                //直接登录
                webSocketService.login(eventKey, user);
                return TextBuilder.build("登录成功", wxMpXmlMessage);
            }
            //已注册未授权
            else {
                WAIT_AUTHORIZE_MAP.put(openId, eventKey);
                //重新授权并登录
                return TextBuilder.build("请点击登录:<a href=\"" + grantUrl + "\">登录</a>", wxMpXmlMessage);
            }
        }
        //未注册
        else {
            //注册,授权并登录
            User userInsert = UserAdapter.buildUser(openId);
            userService.register(userInsert);
            WAIT_AUTHORIZE_MAP.put(openId, eventKey);
            return TextBuilder.build("请点击登录:<a href=\"" + grantUrl + "\">登录</a>", wxMpXmlMessage);
        }
    }

    @Override
    public void authorizeAndLogin(WxOAuth2UserInfo userInfo) {
        String openId = userInfo.getOpenid();
        User user = userDao.getByOpenId(openId);
        if (StrUtil.isBlank(user.getAvatar()) && StrUtil.isBlank(user.getName())) {
            fillUserInfo(user.getId(), userInfo);
        }
        //通过eventKey找到channel登录
        Integer eventKey = WAIT_AUTHORIZE_MAP.remove(openId);
        webSocketService.login(eventKey, user);
    }

    private void fillUserInfo(Long uid, WxOAuth2UserInfo userInfo) {
        User authorizeUser = UserAdapter.buildAuthorizeUser(uid, userInfo);
        //todo 并发异常业务,昵称重复业务完善
        userDao.updateById(authorizeUser);
    }

    /**
     * 去除微信发送eventKey自带的"qrscene_"
     */
    private Integer getEventKey(WxMpXmlMessage wxMpXmlMessage) {
        String qrScene = null;
        try {
            String eventKey = wxMpXmlMessage.getEventKey();
            qrScene = eventKey.replace("qrscene_", "");
            return Integer.parseInt(qrScene);
        } catch (Exception e) {
            log.error("getEventKey error:{}", wxMpXmlMessage.getEventKey(), e);
            return null;
        }
    }
}
